/**
 * @author：anlzou
 * @Date：Created in17:39 2021/3/30
 * @Github：https://github.com/anlzou
 * @Description：
 */
package com.anlzou.demo.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Aspect
@Component
public class LogProxy {

    //在切入点前调用
//    @Before("execution(public int com.anlzou.demo.aop.ArithmeticCalculator.*(int, int))")
    @Pointcut("execution(public int com.anlzou.demo.aop.ArithmeticCalculator.*(int, int))")
    public void beforMethod(JoinPoint point){
        String methodName = point.getSignature().getName();
        List<Object> args = Arrays.asList(point.getArgs());
        System.out.println("@Before===="+"调用前连接点方法为：" + methodName + ",参数为：" + args);
    }

    //在切入点后调用
    @After("execution(public int com.anlzou.demo.aop.ArithmeticCalculator.*(int, int))")
    public void afterMethod(JoinPoint point){
        String methodName = point.getSignature().getName();
        List<Object> args = Arrays.asList(point.getArgs());
        System.out.println("@After===="+"调用前连接点方法为：" + methodName + ",参数为：" + args);
    }

    /*
     * 切入点返回正常结果则调用,在@After之前
     * 通过returning属性指定连接点方法返回的结果放置在result变量中，
     * 在返回通知方法中可以从result变量中获取连接点方法的返回结果了。
     */
    @AfterReturning(value="execution(public int com.anlzou.demo..aop.ArithmeticCalculator.*(int, int))",
            returning="result")
    public void afterReturning(JoinPoint point, Object result){
        String methodName = point.getSignature().getName();
        List<Object> args = Arrays.asList(point.getArgs());
        System.out.println("@AfterReturning===="+"连接点方法为：" + methodName + ",参数为：" + args + ",目标方法执行结果为：" + result);
    }

    /*
    * 切入点异常则调用
    */
    @AfterThrowing(value="execution(public int com.anlzou.demo.aop.ArithmeticCalculator.*(int, int))",
            throwing="ex")
    public void afterThrowing(JoinPoint point, Exception ex){
        String methodName = point.getSignature().getName();
        List<Object> args = Arrays.asList(point.getArgs());
        System.out.println("@AfterThrowing"+"连接点方法为：" + methodName + ",参数为：" + args + ",异常为：" + ex);
    }

    @Around("execution(public int com.anlzou.demo.aop.ArithmeticCalculator.*(int, int))")
    public Object aroundMethod(ProceedingJoinPoint pdj){
        /*result为连接点的放回结果*/
        Object result = null;
        String methodName = pdj.getSignature().getName();

        /*前置通知方法*/
        System.out.println("@Around"+"前置通知方法>目标方法名：" + methodName + ",参数为：" + Arrays.asList(pdj.getArgs()));

        /*执行目标方法*/
        try {
            result = pdj.proceed();

            /*返回通知方法*/
            System.out.println("@Around"+"返回通知方法>目标方法名" + methodName + ",返回结果为：" + result);
        } catch (Throwable e) {
            /*异常通知方法*/
            System.out.println("@Around"+"异常通知方法>目标方法名" + methodName + ",异常为：" + e);
            /*当环绕通知方法本身还有其它异常时，非连接点方法出现的异常，此时抛出来*/
            throw new RuntimeException();
        }

        /*后置通知*/
        System.out.println("@Around"+"后置通知方法>目标方法名" + methodName);

        return result;
    }
}
